package com.xdcplus.web.service.bd.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.exceptions.XdcWebException;
import com.xdcplus.mom.constants.NumberConstant;
import com.xdcplus.mom.enums.ResponseEnum;
import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.mp.utils.PageableUtils;
import com.xdcplus.mp.utils.PropertyUtils;
import com.xdcplus.pager.vo.PageVO;
import com.xdcplus.web.common.pojo.dto.bd.BdPathiDTO;
import com.xdcplus.web.common.pojo.dto.bd.BdPathiFilterDTO;
import com.xdcplus.web.common.pojo.entity.bd.BdMaterial;
import com.xdcplus.web.common.pojo.entity.bd.BdPath;
import com.xdcplus.web.common.pojo.entity.bd.BdPathi;
import com.xdcplus.web.common.pojo.query.bd.BdPathiQuery;
import com.xdcplus.web.common.pojo.vo.bd.BdPathiVO;
import com.xdcplus.web.common.pojo.vo.bd.GetBdPathiVoAndFirstBdPathByPathiIdFkVo;
import com.xdcplus.web.mapper.bd.BdMaterialMapper;
import com.xdcplus.web.mapper.bd.BdPathMapper;
import com.xdcplus.web.mapper.bd.BdPathiMapper;
import com.xdcplus.web.service.bd.BdPathService;
import com.xdcplus.web.service.bd.BdPathiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 工艺路线表(BdPathi)表服务实现类
 *
 * @author Fish.Fei
 * @since 2023-02-03 16:00:51
 */
@Slf4j
@Service("bdPathiService")
public class BdPathiServiceImpl extends BaseServiceImpl<BdPathiMapper, BdPathi, BdPathi, BdPathiVO> implements BdPathiService {

    @Autowired
    protected BdPathiMapper bdPathiMapper;

    @Autowired
    protected BdPathMapper bdPathMapper;

    @Autowired
    protected BdMaterialMapper bdMaterialMapper;
    @Autowired
    private BdPathService bdPathService;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean saveBdPathi(BdPathiDTO bdPathiDTO) {

        Long codeCount = bdPathiMapper.selectCount(
                new QueryWrapper<BdPathi>().eq("PATH_CODE", bdPathiDTO.getPathCode())
                        .or()
                .eq("PATH_DSC", bdPathiDTO.getPathDsc()));
        Assert.isTrue(Validator.equal(codeCount,NumberConstant.ZERO.longValue()),ResponseEnum.CODE_OR_DSC_ALREADY_EXISTS.getMessage());


        BdPathi bdPathi = new BdPathi();
        BeanUtil.copyProperties(bdPathiDTO, bdPathi);
        bdPathi.setCreatedTime(new Timestamp(DateUtil.current()));
        
        return this.save(bdPathi);

    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean updateBdPathi(BdPathiDTO bdPathiDTO) {

        BdPathi bdPathi = this.getById(bdPathiDTO.getId());
        if (ObjectUtil.isNull(bdPathi)) {
            log.error("updateBdPathi() The BdPathi does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }

        /// 判断工艺路线名称是否重复
        LambdaUpdateWrapper<BdPathi> pathiLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        pathiLambdaUpdateWrapper.eq(BdPathi::getPathDsc,bdPathiDTO.getPathDsc());
        pathiLambdaUpdateWrapper.ne(BdPathi::getId,bdPathiDTO.getId());
        if (this.count(pathiLambdaUpdateWrapper)>0) {
            throw new XdcWebException(ResponseEnum.PATHI_DSC_EXISTS);
        }

        BeanUtil.copyProperties(bdPathiDTO, bdPathi);
        bdPathi.setUpdatedUser(bdPathiDTO.getUpdatedUser());
        bdPathi.setUpdatedTime(new Timestamp(DateUtil.current()));

        /// 允许起始工艺传值为空，取消设置
        if (ObjectUtil.isNull(bdPathi.getFirstOpeNo())) {
            bdPathi.setFirstOpeNo(-1L);
        }
        /// 不允许存入null值
        this.updateById(bdPathi);

        if (bdPathi.getFirstOpeNo().equals(-1L)) {
            /// 单独设置null值
            LambdaUpdateWrapper<BdPathi> bdPathiLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            bdPathiLambdaUpdateWrapper.eq(BdPathi::getId,bdPathi.getId());
            bdPathiLambdaUpdateWrapper.set(BdPathi::getFirstOpeNo,"");
            this.update(bdPathiLambdaUpdateWrapper);
        }

        return true;

    }

    @Override
    public Boolean saveOrUpdateBatch(List<BdPathi> bdPathiList) {

        bdPathiList.forEach(bdPathi -> {
            BdPathi bdPathiParam = new BdPathi();
            bdPathiParam.setId(bdPathi.getId());
            if (ObjectUtil.isNotNull(bdPathi.getId())) {
                bdPathi.setId(bdPathi.getId());
                bdPathi.setUpdatedTime(new Timestamp(DateUtil.current()));
                LambdaUpdateWrapper<BdPathi> lambdaUpdate = Wrappers.lambdaUpdate();
                lambdaUpdate.eq(BdPathi::getId, bdPathi.getId());
                update(bdPathi, lambdaUpdate);
            } else {
                bdPathi.setCreatedTime(new Timestamp(DateUtil.current()));
                save(bdPathi);
            }
        });
        return true;
    }

    @Override
    public Boolean saveOrUpdateBatchByDTOList(List<BdPathiDTO> bdPathiDTOList) {

        List<BdPathi> bdPathiList = BeanUtils.copyProperties(bdPathiDTOList, BdPathi.class);
        return saveOrUpdateBatch(bdPathiList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteBdPathiLogical(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        BdPathi bdPathi = this.getById(id);

        if (ObjectUtil.isNull(bdPathi)) {
            log.error("deleteBdPathi() The BdPathi does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }

        /// 验证是否被产品使用
        LambdaQueryWrapper<BdMaterial> bdMaterialLambdaQueryWrapper = new LambdaQueryWrapper<>();
        bdMaterialLambdaQueryWrapper.eq(BdMaterial::getPathiIdFk,id);
        Assert.isTrue(bdMaterialMapper.selectCount(bdMaterialLambdaQueryWrapper).intValue() == NumberConstant.ZERO,
                ResponseEnum.BDPATHI__USED.getMessage());

        /// 是否清除了工序
        LambdaQueryWrapper<BdPath> bdPathLambdaQueryWrapper = new LambdaQueryWrapper<>();
        bdPathLambdaQueryWrapper.eq(BdPath::getPathIdFk,id);
        Assert.isTrue(this.bdPathMapper.selectCount(bdPathLambdaQueryWrapper).intValue() == NumberConstant.ZERO,
                ResponseEnum.BDPATH_EXISTS_ERROR.getMessage());

        return this.removeById(id);
    }
    
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteBdPathiByIds(String ids) {
        Assert.notNull(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
		List<String> idList = Arrays.asList(ids.split(","));
		if(CollectionUtil.isEmpty(idList)){
           throw new XdcWebException(ResponseEnum.ERROR);
       }
		idList.forEach(id->{
			BdPathi bdPathi = this.getById(id);
			if (ObjectUtil.isNull(bdPathi)) {
				log.error("deleteBdPathi() The BdPathi does not exist or has been deleted");
				throw new XdcWebException(ResponseEnum.ERROR);
			}
		});

        /// 工艺路线详情也要删除
        if (!idList.isEmpty()) {
            LambdaQueryWrapper<BdPath> bdPathLambdaQueryWrapper = new LambdaQueryWrapper<>();
            bdPathLambdaQueryWrapper.in(BdPath::getPathIdFk,idList);
            bdPathMapper.delete(bdPathLambdaQueryWrapper);
        }

        return this.removeByIds(idList);

    }

    private List<BdPathi> queryBdPathiList(BdPathiFilterDTO bdPathiFilterDTO) {
        BdPathiQuery bdPathiQuery = BeanUtil.copyProperties(bdPathiFilterDTO, BdPathiQuery.class);

        /// 模糊查询关键字处理
        if (ObjectUtil.isNotEmpty(bdPathiQuery.getPathCode())) {
            bdPathiQuery.setPathCode(bdPathiQuery.getPathCode().replaceAll("_","\\\\_"));
        }
        if (ObjectUtil.isNotEmpty(bdPathiQuery.getPathDsc())) {
            bdPathiQuery.setPathDsc(bdPathiQuery.getPathDsc().replaceAll("_","\\\\_"));
        }
        return bdPathiMapper.queryBdPathi(bdPathiQuery);
    }

    @Override
    public List<BdPathiVO> queryBdPathiVOList(BdPathiFilterDTO bdPathiFilterDTO) {
        return this.objectConversion(queryBdPathiList(bdPathiFilterDTO));
    }

    @Override
    public PageVO<BdPathiVO> queryBdPathi(BdPathiFilterDTO bdPathiFilterDTO) {
        PageVO<BdPathiVO> pageVO = new PageVO<>();

        if (bdPathiFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageableUtils.basicPage(bdPathiFilterDTO.getCurrentPage(), bdPathiFilterDTO.getPageSize(),
                    "DESC nulls last", "CREATED_TIME");
        }else {
            /// 非-1非最值，否则分页，排序不生效；自定义sql排序和分页helper会冲突。
            PageableUtils.basicPage(1, NumberConstant.QUERY_MAX_DATA_SIZE,
                    "DESC nulls last", "CREATED_TIME");
        }

        List<BdPathi> bdPathiList = queryBdPathiList(bdPathiFilterDTO);

        PageInfo<BdPathi> pageInfo = new PageInfo<>(bdPathiList);

        List<BdPathiVO> records = this.objectConversion(bdPathiList);

        // 装配工艺路线的起始工艺名称
        List<Long> bdPathIdList = records.stream().map(BdPathiVO::getFirstOpeNo).filter(ObjectUtil::isNotNull).collect(Collectors.toList());
        if (!bdPathIdList.isEmpty()) {
            List<Map<String, String>> mapList = this.baseMapper.queryOpeNameWithBdPathIds(bdPathIdList);
            if (ObjectUtil.isNotEmpty(mapList)) {
                Map<String, String> bdPathId2OpeNameMap =
                        mapList.stream().collect(Collectors.toMap(
                                keyMap -> keyMap.get("id"),
                                valueMap -> valueMap.get("name")));
                log.info("bdPathId2OpeNameMap: {}",bdPathId2OpeNameMap);
                records.forEach(record -> {
                    if (ObjectUtil.isNotNull(record.getFirstOpeNo())) {
                        record.setFirstOpeName(bdPathId2OpeNameMap.getOrDefault(String.valueOf(record.getFirstOpeNo()),null));
                    }
                });
            }
        }

        PropertyUtils.copyProperties(pageInfo, pageVO, records);

        return pageVO;
    }

    @Override
    public BdPathiVO queryBdPathiById(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.objectConversion(this.getById(id));
    }

    @Override
    public GetBdPathiVoAndFirstBdPathByPathiIdFkVo getBdPathiVoAndFirstBdPathByPathiIdFk(Long pathiIdFk) {
        GetBdPathiVoAndFirstBdPathByPathiIdFkVo getBdPathiVoAndFirstBdPathByPathiIdFkVo=new GetBdPathiVoAndFirstBdPathByPathiIdFkVo();
        BdPathiVO bdPathiVO = this.queryBdPathiById(pathiIdFk);
        Assert.notNull(bdPathiVO, "工艺路线不存在");
        Assert.notNull(bdPathiVO.getFirstOpeNo(), "起始工序未配置");
        BdPath bdPath = bdPathService.getById(bdPathiVO.getFirstOpeNo());
        Assert.notNull(bdPath,"起始工序配置有误");
        getBdPathiVoAndFirstBdPathByPathiIdFkVo.setBdPathiVO(bdPathiVO);
        getBdPathiVoAndFirstBdPathByPathiIdFkVo.setFirstPath(bdPath);
        return getBdPathiVoAndFirstBdPathByPathiIdFkVo;
//        bdPath.getCrOpeCode();
    }
}
